package cn.turboinfo.fuyang.api.provider.common.service.impl.role;

import cn.turboinfo.fuyang.api.domain.common.service.role.RoleService;
import cn.turboinfo.fuyang.api.entity.admin.exception.user.RoleException;
import cn.turboinfo.fuyang.api.entity.admin.pojo.role.Role;
import cn.turboinfo.fuyang.api.entity.admin.pojo.role.RoleCreator;
import cn.turboinfo.fuyang.api.entity.admin.pojo.role.RoleUpdater;
import cn.turboinfo.fuyang.api.provider.common.repository.database.role.RoleDAO;
import cn.turboinfo.fuyang.api.provider.common.repository.database.role.RolePO;
import cn.turboinfo.fuyang.api.provider.common.repository.database.role.RolePermissionDAO;
import cn.turboinfo.fuyang.api.provider.common.repository.database.role.RolePermissionPO;
import cn.turboinfo.fuyang.api.provider.common.repository.database.user.SysUserRoleDAO;
import cn.turboinfo.fuyang.api.provider.common.repository.database.user.SysUserRolePO;
import lombok.RequiredArgsConstructor;
import net.sunshow.toolkit.core.base.enums.YesNoStatus;
import net.sunshow.toolkit.core.qbean.api.request.QPage;
import net.sunshow.toolkit.core.qbean.api.request.QRequest;
import net.sunshow.toolkit.core.qbean.api.response.QResponse;
import net.sunshow.toolkit.core.qbean.helper.component.request.QBeanCreatorHelper;
import net.sunshow.toolkit.core.qbean.helper.component.request.QBeanUpdaterHelper;
import net.sunshow.toolkit.core.qbean.helper.service.impl.AbstractQServiceImpl;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

@RequiredArgsConstructor
@Service
public class RoleServiceImpl extends AbstractQServiceImpl<Role> implements RoleService {
    private final RoleDAO roleDAO;

    private final SysUserRoleDAO sysUserRoleDAO;

    private final RolePermissionDAO rolePermissionDAO;

    @Override
    public Optional<Role> getById(Long id) {
        return roleDAO.findById(id).map(this::convertQBean);
    }

    @Override
    public Role getByIdEnsure(Long id) throws RoleException {
        return getById(id).orElseThrow(this.getExceptionSupplier("角色不存在, id=" + id, null));
    }

    @Override
    public Optional<Role> getByCode(String code) {
        return roleDAO.findByCode(code).map(this::convertQBean);
    }

    @Override
    @Transactional
    public Role save(RoleCreator creator) throws RoleException {
        RolePO rolePO = new RolePO();

        QBeanCreatorHelper.copyCreatorField(rolePO, creator);

        return convertQBean(roleDAO.save(rolePO));
    }

    @Override
    @Transactional
    public Role update(RoleUpdater updater) throws RoleException {
        RolePO rolePO = getEntityWithNullCheckForUpdate(updater.getUpdateId(), roleDAO);

        // 系统保留角色不允许编辑
        if (rolePO.getIsReserved() == YesNoStatus.YES) {
            throw getExceptionSupplier("系统保留角色不允许编辑", null).get();
        }

        QBeanUpdaterHelper.copyUpdaterField(rolePO, updater);

        return convertQBean(rolePO);
    }

    @Override
    public QResponse<Role> findAll(QRequest request, QPage requestPage) {
        return convertQResponse(findAllInternal(request, requestPage));
    }

    private Page<RolePO> findAllInternal(QRequest request, QPage requestPage) {
        return roleDAO.findAll(convertSpecification(request), convertPageable(requestPage));
    }

    @Override
    public List<Role> findAll() {
        return roleDAO.findAllByOrderByIdAsc().stream().map(this::convertQBean).collect(Collectors.toList());
    }

    @Override
    @Transactional
    public void deleteById(Long id) throws RoleException {
        RolePO rolePO = getEntityWithNullCheckForUpdate(id, roleDAO);

        // 系统保留角色不允许删除
        if (rolePO.getIsReserved() == YesNoStatus.YES) {
            throw getExceptionSupplier("系统保留角色不允许删除", null).get();
        }

        // 删除为此角色分配的权限记录
        List<RolePermissionPO> rolePermissionPOList = rolePermissionDAO.findByRoleId(rolePO.getId());
        rolePermissionDAO.deleteAll(rolePermissionPOList);

        // 删除已分配给用户的角色记录
        List<SysUserRolePO> sysUserRolePOList = sysUserRoleDAO.findByRoleId(rolePO.getId());
        sysUserRoleDAO.deleteAll(sysUserRolePOList);

        roleDAO.delete(rolePO);
    }

    @Override
    public List<Role> findByIdCollection(Collection<Long> idCollection) {
        return StreamSupport.stream(roleDAO.findAllById(idCollection).spliterator(), false)
                .map(this::convertQBean)
                .collect(Collectors.toList());
    }

    @Override
    public List<Role> findByCodeCollection(Collection<String> codeCollection) {
        return convertStreamQBeanToList(roleDAO.findByCodeInOrderByIdAsc(codeCollection).stream());
    }

    @Override
    protected Supplier<? extends RuntimeException> getExceptionSupplier(String message,
                                                                        Throwable cause) {
        return () -> new RoleException(message, cause);
    }
}
